using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

namespace UnitTests
{
	public class MyXmlDocument : XmlDocument
	{
		private XmlNamespaceManager manager = null;

		public MyXmlDocument()
		{
		}

		private static string regexPattern = @"((?<prefix>\w*):)?(?<name>\w*)(\[(@(?<attr>\w*)='(?<value>\w*)'( and )?)+\])?";

		public XmlNode WriteElement(XmlNode parent, string xpath)
		{
			if (xpath.StartsWith("/"))
			{
				xpath = xpath.Substring(1);
			}
			return WriteElement(parent, xpath.Split('/'));
		}

		public XmlNode WriteElement(XmlNode parent, params string[] pathElements)
		{
			string myPath = pathElements[0];
			XmlNode node = null;

			if (parent.ChildNodes.Count > 0)
				node = parent.SelectSingleNode(myPath);

			if (node == null)
			{
				Regex regex = new Regex(regexPattern, RegexOptions.ExplicitCapture);
				MatchCollection matchCollection = regex.Matches(myPath);
				Match match = regex.Match(myPath);
				CaptureCollection collection = match.Captures;

				string name = match.Groups["name"].Value;
				string[] attributes = new string[0];
				string[] values = new string[0];
				if (!string.IsNullOrEmpty(match.Groups["attr"].Value))
				{
					attributes = new string[] {match.Groups["attr"].Value};
					values = new string[] {match.Groups["value"].Value};
				}
				node = AppendElement(parent, name, attributes, values);
			}

			if (pathElements.Length == 1)
			{
				return node;
			}

			else
			{
				string[] newElements = new string[pathElements.Length - 1];
				for (int i = 1; i < pathElements.Length; i++)
				{
					newElements[i - 1] = pathElements[i];
				}
				return WriteElement(node, string.Join("/", newElements));
			}
		}

		private string prefix = "x";

		public MyXmlDocument(string defNamespace)
		{
			manager = new XmlNamespaceManager(NameTable);
			manager.AddNamespace(prefix, defNamespace);
			manager.AddNamespace("", defNamespace);
		}

		private XmlNode AppendElement(XmlNode parent, string name, params string[] attributes)
		{
			XmlElement element;
			if (manager != null)
				element = parent.OwnerDocument.CreateElement(name, manager.DefaultNamespace);
			else
				element = parent.OwnerDocument.CreateElement(name);

			foreach (string s in attributes)
			{
				element.Attributes.Append(parent.OwnerDocument.CreateAttribute(s));
			}
			parent.AppendChild(element);
			return element;
		}

		public XmlNode AppendElement(XmlNode parent, string name, string[] attributes, params string[] values)
		{
			XmlNode node = AppendElement(parent, name, attributes);
			for (int i = 0; i < attributes.Length; i++)
			{
				node.Attributes[attributes[i]].Value = values[i];
			}
			return node;
		}

		public void Write(string fileName)
		{
			using (XmlTextWriter writer = GetWriter(fileName))
				WriteTo(writer);
		}

		private static XmlTextWriter GetWriter(string fileName)
		{
			XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.Default);
			writer.Formatting = Formatting.Indented;
			return writer;
		}
	}
}